package model

import (
	"time"

	"wxpay/pkg/util"
)

const (
	/*
		发给域外的消息
	*/
	// 支付通知
	TopicPayedNotify = "wxpay-trade_payed"
	// 退款通知
	TopicRefundNotify = "wxpay-refund_notify"
	// 分账通知
	TopicProfitOrderNotify = "wxpay-profit_order"
	// 分账回退通知
	TopicProfitReturnNotify = "wxpay-profit_return"
	// 进件结果通知
	TopicApplymentNotify = "wxpay-apply_notify"
	// 二级商户提现通知
	TopicWithdrawNotify = "wxpay-withdraw_notify"
	/*
		域内外共享的消息
	*/
	// 批量转账（到用户零钱）通知
	TopicTransferNotify = "wxpay-transfer_notify"
	// 微信特约商户进件终态消息
	TopicSubMchApplymentNotify = "wxpay-sub_mch_applyment_notify"
	/*
		域内消费的消息
	*/
	// 消息重试
	TopicMessageRetry = "wxpay-message_retry"
	// 发起转账任务
	TopicTransferAction = "wxpay-transfer_action"
	// 发起提现任务
	TopicWithdrawAction = "wxpay-withdraw_submit"
	// 提现查询
	TopicWithdrawQuery = "wxpay-withdraw_query"
	// 进件查询
	TopicApplymentQuery = "wxpay-applyment_query"
	// 交易查询
	TopicTradeQuery = "wxpay-trade_query"
	// 退款查询
	TopicRefundQuery = "wxpay-refund_query"
	// 分账订单查询
	TopicProfitOrderQuery = "wxpay-profit_order_query"
	// 分账回退查询
	TopicProfitReturnQuery = "wxpay-profit_return_query"
	// 转账查询
	TopicTransferQuery = "wxpay-transfer_query"
	// 支付当面付申请消息
	TopicAliFaceToFaceSignQuery = "wxpay-ali_facetoface_siqn_query"
	// 微信特约商户进件查询
	TopicSubMchApplymentQuery = "wxpay-sub_mch_applyment_query"
)

var ListenTopics = [...]string{
	//域内的消息
	TopicMessageRetry,
	TopicTransferAction,
	TopicWithdrawAction,
	TopicWithdrawQuery,
	TopicApplymentQuery,
	TopicTradeQuery,
	TopicRefundQuery,
	TopicProfitOrderQuery,
	TopicProfitReturnQuery,
	TopicTransferQuery,
	TopicTransferNotify,
}

type RetryMessage struct {
	ID int64 `json:"id"`
}

// 支付成功通知参数
type PayNotification struct {
	// 商户ID
	BrandID string `json:"brand_id"`
	// 服务商公众号ID
	AppID string `json:"app_id"`
	// 服务商户号
	MchID string `json:"mch_id"`
	// 二级商户公众号ID
	SubAppID string `json:"sub_app_id"`
	// 二级商户号
	SubMchID string `json:"sub_mch_id"`
	// 商户订单号
	OutTradeNo string `json:"out_trade_no"`
	// 微信支付订单号
	TransactionID string `json:"transaction_id"`
	// 交易类型
	TradeType string `json:"trade_type"`
	// 交易状态
	TradeState string `json:"trade_state"`
	// 交易状态描述
	TradeStateDesc string `json:"trade_state_desc"`
	// 附加数据
	Attach string `json:"attach"`
	// 支付完成时间
	SuccessTime string `json:"success_time"`
	// 消息时间戳
	Timestamp int64 `json:"timestamp"`
	// 服务费率 * 10000
	ServiceRate int64 `json:"service_rate"`
	// 服务费
	ServiceFee int64 `json:"service_fee"`
}

func NewPayNotification(t *Trade) (pn *PayNotification) {
	pn = &PayNotification{
		BrandID:        t.BrandID,
		AppID:          t.AppID,
		MchID:          t.MchID,
		SubAppID:       util.ConvertNullString(t.SubAppID),
		SubMchID:       t.SubMchID,
		OutTradeNo:     t.OutTradeNo,
		TransactionID:  util.ConvertNullString(t.WxTransID),
		TradeType:      util.ConvertNullString(t.TradeType),
		TradeState:     util.ConvertNullString(t.TradeState),
		TradeStateDesc: util.ConvertNullString(t.TradeStateDesc),
		Attach:         t.Description,
		SuccessTime:    util.TimePtrToString(t.SuccessTime, util.LayoutSecondWithTimeZoneAndT),
		ServiceRate:    t.GetServiceRate(),
		ServiceFee:     *t.GetServiceFee(),
		Timestamp:      t.UpdateTime.Unix(),
	}
	return
}

// 退款变更通知
type RefundNotification struct {
	// 商户ID
	BrandID string `json:"brand_id"`
	// 服务商公众号ID
	AppID string `json:"app_id"`
	// 服务商户号
	MchID string `json:"mch_id"`
	// 二级商户公众号ID
	SubAppID string `json:"sub_app_id"`
	// 二级商户号
	SubMchID string `json:"sub_mch_id"`
	// 商户订单号
	OutTradeNo string `json:"out_trade_no"`
	// 微信支付订单号
	TransactionID string `json:"transaction_id"`
	// 商户退款单号
	OutRefundNo string `json:"out_refund_no"`
	// 微信退款单号
	RefundID string `json:"refund_id"`
	// 退款状态
	RefundStatus string `json:"refund_status"`
	// 退款成功时间
	SuccessTime string `json:"success_time"`
	// 退款入账账户
	UserReceivedAccount string `json:"user_received_account"`
	// 金额信息
	Amount RefundNotifyAmount `json:"amount"`
	// 消息时间戳
	Timestamp int64 `json:"timestamp"`
	// 退回服务费
	ServiceFeeReturn int64 `json:"service_fee_return"`
}

type RefundNotifyAmount struct {
	// 订单金额
	Total uint `json:"total"`
	// 退款金额
	Refund uint `json:"refund"`
	// 用户支付金额
	PayerTotal uint `json:"payer_total,omitempty"`
	// 用户退款金额
	PayerRefund uint `json:"payer_refund,omitempty"`
}

func NewRefundNotification(t *Refund) (rn *RefundNotification) {
	amountInfo := t.GetRefundAmount()
	rn = &RefundNotification{
		BrandID:             t.BrandID,
		AppID:               t.AppID,
		MchID:               t.MchID,
		SubAppID:            util.ConvertNullString(t.SubAppID),
		SubMchID:            t.SubMchID,
		OutTradeNo:          t.OutTradeNo,
		TransactionID:       t.WxTransID,
		OutRefundNo:         t.OutRefundNo,
		RefundID:            util.ConvertNullString(t.RefundID),
		RefundStatus:        util.ConvertNullString(t.Status),
		SuccessTime:         util.TimePtrToString(t.SuccessTime, util.LayoutSecondWithTimeZoneAndT),
		UserReceivedAccount: util.ConvertNullString(t.UserReceivedAccount),
		Amount: RefundNotifyAmount{
			Total:       amountInfo.Total,
			Refund:      amountInfo.Refund,
			PayerTotal:  amountInfo.PayerTotal,
			PayerRefund: amountInfo.PayerRefund,
		},
		Timestamp:        t.UpdateTime.Unix(),
		ServiceFeeReturn: t.GetServiceFeeReturn(),
	}
	return
}

type ReceiverInProfitShare struct {
	// 分账接收方类型
	Type string `json:"type"`
	// 分账接收方帐号
	Account string `json:"account"`
	// 分账动账金额
	Amount int64 `json:"amount"`
	// 分账/回退描述
	Description string `json:"description"`
	// 分账接受方姓名
	ReceiverName string `json:"receiver_name"`
}

// 分账变更消息
type ProfitOrderNotification struct {
	// 品牌id
	BrandID string `json:"brand_id"`
	// 商户订单编号
	OutTradeNo string `json:"out_trade_no"`
	// 商户分账单号
	OutOrderNo string `json:"out_order_no"`
	// 二级商户商户号
	SubMchID string `json:"sub_mch_id"`
	// 分账接受方
	Receivers []ReceiverInProfitShare `json:"receivers"`
	// 是否完结分账
	Finish bool `json:"finish"`
	// 微信分账单号
	WxOrderID string `json:"wx_order_id"`
	// 服务商商户号
	MchID string `json:"mch_id"`
	// 服务商appid
	AppID string `json:"app_id"`
	// 微信支付单号
	WxTransID string `json:"wx_trans_id"`
	// 分账完结描述(仅分账完结有)
	FinishDescription string `json:"finish_description,omitempty"`
	// 分账失败原因(仅分账失败有)
	CloseReason string `json:"close_reason,omitempty"`
	// 分账完成金额(仅分账完结有)
	FinishAmount string `json:"finish_amount,omitempty"`
	// 分账单状态
	Status string `json:"status"`
	// 消息时间戳
	Timestamp int64 `json:"timestamp"`
}

func NewProfitOrderNotification(p *Profitshare) (r *ProfitOrderNotification) {
	var rcvs []ReceiverInProfitShare
	if !p.IsFinishOrder() {
		// 只有分账完结订单才有接受者
		receivers := p.GetReceivers()
		rcvs = make([]ReceiverInProfitShare, len(receivers))
		for i, rcv := range receivers {
			rcvs[i] = ReceiverInProfitShare(rcv)
		}
	}
	return &ProfitOrderNotification{
		BrandID:           p.BrandID,
		OutTradeNo:        p.OutTradeNo,
		OutOrderNo:        p.OutOrderNo,
		SubMchID:          p.SubMchID,
		Receivers:         rcvs,
		Finish:            p.IsFinishOrder(),
		MchID:             p.MchID,
		AppID:             p.AppID,
		WxTransID:         p.WxTransID,
		WxOrderID:         util.ConvertNullString(p.WxOrderID),
		FinishDescription: util.ConvertNullString(p.FinishDescription),
		CloseReason:       util.ConvertNullString(p.CloseReason),
		FinishAmount:      util.ConvertNullInt64(p.FinishAmount),
		Status:            util.ConvertNullString(p.Status),
		Timestamp:         p.UpdateTime.Unix(),
	}
}

// 分账回退变更消息
type ProfitReturnNotification struct {
	// 品牌id
	BrandID string `json:"brand_id"`
	// 商户分账单号
	OutOrderNo string `json:"out_order_no"`
	// 二级商户商户号
	SubMchID string `json:"sub_mch_id"`
	// 商户回退单号
	OutReturnNo string `json:"out_return_no"`
	// 回退商户ID
	ReturnMchID string `json:"return_mch_id"`
	// 回退金额
	Amount int64 `json:"amount"`
	// 回退描述
	Description string `json:"description"`
	// 微信回退单号
	WxReturnNo string `json:"wx_return_no"`
	// 微信分账单id
	WxOrderID string `json:"wx_order_id"`
	// 服务商AppID
	AppID string `json:"app_id"`
	// 服务商商户号
	MchID string `json:"mch_id"`
	// 回退结果: "PROCESSING","SUCCESS","FAIL"
	Result string `json:"result"`
	// 失败原因 字段仅回退结果为FAIL时存在，枚举值：
	//		ACCOUNT_ABNORMAL：分账接收方账户异常
	//		TIME_OUT_CLOSED：超时关单
	FailReason string `json:"fail_reason"`
	// 完成时间 格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE
	FinishTime *time.Time `json:"finish_time"`
	// 消息时间戳
	Timestamp int64 `json:"timestamp"`
}

func NewProfitReturnNotification(p *Profitreturn) (r *ProfitReturnNotification) {
	return &ProfitReturnNotification{
		BrandID:     p.BrandID,
		OutOrderNo:  p.OutOrderNo,
		SubMchID:    p.SubMchID,
		OutReturnNo: p.OutReturnNo,
		ReturnMchID: p.ReturnMchID,
		Amount:      p.Amount,
		Description: p.Description,
		WxReturnNo:  util.ConvertNullString(p.WxReturnNo),
		WxOrderID:   p.WxOrderID,
		AppID:       p.AppID,
		MchID:       p.MchID,
		Result:      util.ConvertNullString(p.Result),
		FailReason:  util.ConvertNullString(p.FailReason),
		FinishTime:  p.FinishTime,
		Timestamp:   p.UpdateTime.Unix(),
	}
}

// 批量转账任务
type TransferAwaitAction struct {
	OutBatchNo string `json:"out_batch_no"`
}

func NewTransferCreatedAction(t *Transfer) (r *TransferAwaitAction) {
	return &TransferAwaitAction{OutBatchNo: t.OutBatchNo}
}

// 提现任务
type SubMchWithdrawTask struct {
	OutRequestNo string `json:"out_request_no"`
}

func NewSubMchWithdrawTask(t *SubMchWithdraw) (r *SubMchWithdrawTask) {
	return &SubMchWithdrawTask{OutRequestNo: t.OutRequestNo}
}

// 提现查询任务
type SubMchWithdrawQueryTask struct {
	OutRequestNo string `json:"out_request_no"`
}

func NewSubMchWithdrawQueryTask(t *SubMchWithdraw) (r *SubMchWithdrawQueryTask) {
	return &SubMchWithdrawQueryTask{OutRequestNo: t.OutRequestNo}
}

// 进件查询任务
type ApplymentQueryTask struct {
	ApplyNo string `json:"apply_no"`
}

func NewApplymentQueryTask(t *Applyment) (r *ApplymentQueryTask) {
	return &ApplymentQueryTask{ApplyNo: t.ApplyNo}
}

// 交易查询任务
type TradeQueryTask struct {
	OutTradeNo string `json:"out_trade_no"`
}

func NewTradeQueryTask(t *Trade) (r *TradeQueryTask) {
	return &TradeQueryTask{OutTradeNo: t.OutTradeNo}
}

// 退款查询任务
type RefundQueryTask struct {
	OutRefundNo string `json:"out_refund_no"`
}

func NewRefundQueryTask(t *Refund) (r *RefundQueryTask) {
	return &RefundQueryTask{OutRefundNo: t.OutRefundNo}
}

// 分账查询任务
type ProfitOrderQueryTask struct {
	OutOrderNo string `json:"out_order_no"`
}

func NewProfitOrderQueryTask(p *Profitshare) (r *ProfitOrderQueryTask) {
	return &ProfitOrderQueryTask{OutOrderNo: p.OutOrderNo}
}

// 分账回退查询任务
type ProfitReturnQueryTask struct {
	OutReturnNo string `json:"out_return_no"`
}

func NewProfitReturnQueryTask(p *Profitreturn) (r *ProfitReturnQueryTask) {
	return &ProfitReturnQueryTask{OutReturnNo: p.OutReturnNo}
}

// 批量转账查询任务
type TransferQueryTask struct {
	OutBatchNo string `json:"out_batch_no"`
}

func NewTransferQueryTask(p *Transfer) (r *TransferQueryTask) {
	return &TransferQueryTask{OutBatchNo: p.OutBatchNo}
}

// 进件状态更新通知
type ApplymentNotification struct {
	ApplyNo            string `json:"apply_no"`
	BizApplyNo         string `json:"biz_apply_no"`
	BrandID            string `json:"brand_id"`
	MchID              string `json:"mch_id"`
	SubMchID           string `json:"sub_mch_id"`
	ApplymentType      string `json:"applyment_type"`
	ApplymentState     string `json:"applyment_state"`
	ApplymentStateDesc string `json:"applyment_state_desc"`
	Timestamp          int64  `json:"timestamp"`
}

func NewApplymentNotification(apply *Applyment) (notify *ApplymentNotification) {
	return &ApplymentNotification{
		ApplyNo:            apply.ApplyNo,
		BizApplyNo:         apply.BizApplyNo,
		BrandID:            apply.BrandID,
		MchID:              apply.MchID,
		SubMchID:           util.ConvertNullString(apply.SubMchID),
		ApplymentType:      apply.ApplymentType,
		ApplymentState:     util.ConvertNullString(apply.ApplyState),
		ApplymentStateDesc: util.ConvertNullString(apply.ApplyStateDesc),
		Timestamp:          apply.UpdateTime.Unix(),
	}
}

// SubMchWithdrawNotification - 提现更新通知
type SubMchWithdrawNotification struct {
	// 品牌ID
	BrandID string `json:"brand_id"`
	// 商户号
	MchID string `json:"mch_id"`
	// 子商户号
	SubMchID string `json:"sub_mch_id"`
	// 提现业务单号（本系统）
	OutRequestNo string `json:"out_request_no"`
	// 微信提现ID（微信生成）
	WxWithdrawID string `json:"wx_withdraw_id"`
	// 业务提现ID（业务方生成）
	BizWithdrawID string `json:"biz_withdraw_id"`
	// 提现状态
	// CREATE_SUCCESS：受理成功
	// SUCCESS：提现成功
	// FAIL：提现失败
	// REFUND：提现退票
	// CLOSE：关单
	// INIT：业务单已创建
	Status    string `json:"status"`
	Timestamp int64  `json:"timestamp"`
}

// NewSubMchWithdrawNotification - New方法
func NewSubMchWithdrawNotification(w *SubMchWithdraw) *SubMchWithdrawNotification {
	return &SubMchWithdrawNotification{
		BrandID:       w.BrandID,
		MchID:         w.MchID,
		SubMchID:      w.SubMchID,
		OutRequestNo:  w.OutRequestNo,
		WxWithdrawID:  util.ConvertNullString(w.WxWithdrawID),
		BizWithdrawID: w.BizWithdrawID,
		Status:        w.Status,
		Timestamp:     w.UpdateTime.Unix(),
	}
}

// 转账通知
type BatchTransferNotification struct {
	// 转账成功的订单
	SuccessOrders TransferOrders `json:"success_orders"`
	// 转账失败的订单
	FailedOrders TransferOrders `json:"failed_orders"`
	// 时间戳
	Timestamp int64 `json:"timestamp"`
	// 批次号
	OutBatchNo string `json:"out_batch_no"`
}

type TransferOrders []*transferOrder

// 转账订单详情
type transferOrder struct {
	// 订单号
	OutDetailNo string `json:"out_detail_no"`
	// 业务订单号
	BizDetailNo string `json:"biz_detail_no"`
	// 金额
	Amount int64 `json:"amount"`
	// 备注
	Remark string `json:"remark"`
	// 用户openID
	OpenID string `json:"open_id"`
	// 状态 "SUCCESS" "FAIL"
	Status string `json:"status"`
	// 失败原因
	FailReason string `json:"fail_reason"`
}

func newTransferOrders(ds []*TransferDetail) TransferOrders {
	r := make(TransferOrders, len(ds))
	for i := range ds {
		r[i] = &transferOrder{
			OutDetailNo: ds[i].OutDetailNo,
			BizDetailNo: ds[i].BizDetailNo,
			Amount:      ds[i].Amount,
			Remark:      ds[i].Remark,
			OpenID:      ds[i].OpenID,
			Status:      ds[i].Status,
			FailReason:  util.ConvertNullString(ds[i].FailReason),
		}
	}
	return r
}

func NewBatchTransferNotification(o *Transfer, sList []*TransferDetail, fList []*TransferDetail) BatchTransferNotification {
	return BatchTransferNotification{
		SuccessOrders: newTransferOrders(sList),
		FailedOrders:  newTransferOrders(fList),
		Timestamp:     o.UpdateTime.Unix(),
		OutBatchNo:    o.OutBatchNo,
	}
}

// 支付宝单面付进件查询任务
type AliFaceToFaceSignQueryTask struct {
	ApplyNo string `json:"apply_no"`
}

func NewAliFaceToFaceSignQueryTask(t *AlipayAgentSign) (r *AliFaceToFaceSignQueryTask) {
	return &AliFaceToFaceSignQueryTask{ApplyNo: t.ApplyNo}
}

// 特约商户进件查询任务
type SubMchApplymentQueryTask struct {
	ApplyNo string `json:"apply_no"`
}

func NewSubMchApplymentQueryTask(t *Applyment) (r *SubMchApplymentQueryTask) {
	return &SubMchApplymentQueryTask{ApplyNo: t.ApplyNo}
}
